package com.hk.core.data.orm.aspect;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.orm.ObjectOptimisticLockingFailureException;

/**
 * 数据库乐观锁 Aspect
 *
 * @author Kevin
 * @see RetryOnOptimisticLockingFailure
 * @see jakarta.persistence.Version
 */
@Aspect
public class OptimisticLockInterceptor {

    @Pointcut("@annotation(RetryOnOptimisticLockingFailure)")
    public void retryOnOptFailure() {
    }

    @Around("retryOnOptFailure()")
    public Object doConcurrentOperation(ProceedingJoinPoint pjp) throws Throwable {
        if (pjp.getSignature() instanceof MethodSignature signature) {
            var failure = signature.getMethod().getAnnotation(RetryOnOptimisticLockingFailure.class);
            var maxRetryAttempts = Math.max(1, failure.maxRetryAttempts()); // 最小试一次
            for (var i = 0; i < maxRetryAttempts; i++) {
                try {
                    return pjp.proceed();
                } catch (ObjectOptimisticLockingFailureException e) {
                    /*
                        使用 @javax.persistence.Version 乐观锁控制，当多个线程同时更新同一版本的资源时， 只会有一个线程能执行成功，
                        其它线程执行失败后，会抛出 ObjectOptimisticLockingFailureException
                     */
                    //如果是最后一次了直接抛出 Exception
                    if (i == maxRetryAttempts - 1) {
                        throw e;
                    }
                }
            }
            return null;
        }
        throw new UnsupportedOperationException("pjp.getSignature() did not return a MethodSignature");
    }
}
